from flask import Flask, request, jsonify
import joblib
import pandas as pd
import numpy as np
from data_process import DataProcessor
from tensorflow.keras.models import load_model

# 初始化Flask应用
app = Flask(__name__)

# 加载模型与数据处理器（工单编号：大数据-用户画像-18-京东评论情感预测）
print("加载模型与数据处理器...")
# 传统模型
lr_model = joblib.load('model_saved/logistic_regression.pkl')
rf_model = joblib.load('model_saved/random_forest.pkl')
# LSTM模型
lstm_model = load_model('model_saved/lstm_model.h5')
# 数据处理器（用于特征处理）
processor = DataProcessor()
# 加载商品信息（用于类目特征）
product_info = pd.read_csv('data/商品信息.csv',
                           usecols=['产品ID（PRODUCT_0）', '所属类别'],
                           dtype={'产品ID（PRODUCT_0）': str, '所属类别': str})
product_info['一级类目'] = product_info['所属类别'].str.split(',').str[0]


# 模型融合函数（与训练模块一致）
def weighted_vote(lr_pred, rf_pred, lstm_pred, weights):
    """加权投票预测"""
    score = lr_pred * weights['lr'] + rf_pred * weights['rf'] + lstm_pred * weights['lstm']
    return round(max(1, min(5, score)))


# 预定义模型权重（从训练结果获取）
MODEL_WEIGHTS = {
    'lr': 0.3,  # 示例权重，需替换为实际训练的验证集F1占比
    'rf': 0.4,
    'lstm': 0.3
}


@app.route('/api/sentiment/predict', methods=['POST'])
def predict_sentiment():
    """
    情感预测接口（需求文档3.4部署功能）
    请求参数：user_id, product_id, comment_title, comment_content, comment_timestamp
    响应参数：code, message, data（含预测评分）
    工单编号：大数据-用户画像-18-京东评论情感预测
    """
    try:
        # 1. 获取请求参数
        req_data = request.json
        required_fields = ['user_id', 'product_id', 'comment_title', 'comment_content', 'comment_timestamp']
        for field in required_fields:
            if field not in req_data:
                return jsonify({
                    'code': 400,
                    'message': f'缺少必填参数：{field}',
                    'data': {}
                })

        # 2. 构造输入数据（模拟单条数据，适配处理器）
        input_data = pd.DataFrame({
            '用户ID': [req_data['user_id']],
            '商品ID': [req_data['product_id']],
            '评论时间戳': [req_data['comment_timestamp']],
            '评论标题': [req_data['comment_title']],
            '评论内容': [req_data['comment_content']],
            '评分': [3]  # 占位符，无实际意义
        })

        # 3. 数据预处理（特征工程）
        # 文本特征（TF-IDF）
        input_data['文本合并'] = input_data['评论标题'] + ' ' + input_data['评论内容']
        tfidf_input = processor.tfidf.transform(input_data['文本合并']).toarray()

        # 时间特征
        def extract_time_features(timestamp):
            dt = pd.to_datetime(timestamp, unit='s')
            return pd.Series([dt.hour, dt.dayofweek, dt.month], index=['小时', '星期', '月份'])

        time_input = input_data['评论时间戳'].apply(extract_time_features).values

        # 类目特征（独热编码）
        category = product_info[product_info['产品ID（PRODUCT_0）'] == req_data['product_id']]['一级类目'].values
        category_input = pd.get_dummies([category[0] if len(category) > 0 else '未知'], prefix='类目')
        # 确保与训练集类目特征一致（示例：假设训练集类目包含“家电”“服装”等，此处补全）
        train_categories = ['类目_家电', '类目_服装', '类目_食品', '类目_图书']  # 需替换为实际训练集类目
        for cat in train_categories:
            if cat not in category_input.columns:
                category_input[cat] = 0
        category_input = category_input[train_categories].values

        # 合并特征并筛选、标准化
        X_input = np.hstack([tfidf_input, time_input, category_input])
        X_input_var = processor.var_selector.transform(X_input)
        X_input_scaled = processor.scaler.transform(X_input_var)

        # LSTM序列特征（模拟，实际需用原始文本分词编码）
        X_input_lstm = np.random.randint(0, 10000, (1, 100))  # 词汇表大小10000，序列长度100

        # 4. 多模型预测
        # 逻辑回归预测
        lr_pred = lr_model.predict(X_input_scaled)[0]
        # 随机森林预测
        rf_pred = rf_model.predict(X_input_scaled)[0]
        # LSTM预测（转回1-5分）
        lstm_pred_proba = lstm_model.predict(X_input_lstm)
        lstm_pred = np.argmax(lstm_pred_proba, axis=1)[0] + 1  # 0-4 → 1-5

        # 5. 模型融合预测
        final_pred = weighted_vote(lr_pred, rf_pred, lstm_pred, MODEL_WEIGHTS)

        # 6. 返回结果
        return jsonify({
            'code': 200,
            'message': '预测成功',
            'data': {
                'user_id': req_data['user_id'],
                'product_id': req_data['product_id'],
                'comment_timestamp': req_data['comment_timestamp'],
                'sentiment_score': final_pred  # 最终情感评分（1-5）
            }
        })

    except Exception as e:
        return jsonify({
            'code': 500,
            'message': f'预测失败：{str(e)}',
            'data': {}
        })


if __name__ == '__main__':
    # 启动服务（默认端口5000）
    print("情感预测接口启动，地址：http://127.0.0.1:5000/api/sentiment/predict")
    app.run(debug=True, host='0.0.0.0', port=5000)




